package com.yixiu.modules.db.datasources.aspect;

import com.yixiu.modules.db.datasources.DataSourceNames;
import com.yixiu.modules.db.datasources.DynamicDataSource;
import com.yixiu.modules.db.datasources.annotation.DataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * 定义切面
 */
@Aspect
@Component  //遗漏了。  把普通pojo实例化到spring容器中
 public class DataSourceAspect implements Ordered {

    Logger logger  = LoggerFactory.getLogger(DataSourceAspect.class);

    /**
     * 定义切入点：针对使用了 @DataSource 注解的bean都会进入到这个切入点中
     */
    @Pointcut("@annotation(com.yixiu.modules.db.datasources.annotation.DataSource)")
    public void dataSourcePointCut() {
        //TODO  这个方法是不会执行的
        logger.debug("执行目标函数" );
    }


    /**
     * 针对拦截点dataSourcePointCut进行环绕拦截，可以在目标方法执行前和执行后都拦截
     * @return
     */
    @Around("dataSourcePointCut()")
    public Object  around(ProceedingJoinPoint point) throws Throwable {

        // 通过方法签名获取 对象方法
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();

        // 通过 对象方法 反射，获取 对象 本身
        DataSource ds = method.getAnnotation(DataSource.class);
        if(ds == null) {
            // 如果数据源为空，就默认为第1个
            logger.debug("数据源为空，默认为" + DataSourceNames.FIRST);
            DynamicDataSource.setDataSource(DataSourceNames.FIRST);

        } else {
            // 否则，就使用注解的数据源名称设置动态数据源
            logger.debug("设置数据源为" + ds.name());
            DynamicDataSource.setDataSource(ds.name());
        }
        try {
            // 执行目标函数，并返回
            return point.proceed();
        } finally {
            // 执行完目标函数，清理掉数据源
            logger.debug("执行目标函数后，清理数据源");
            DynamicDataSource.clearDataSource();
        }
    }

    @Override
    public int getOrder() {
        //  实现了Ordered接口的对象优先级高；getOrder()返回值小的优先级高
        //   OrderComparator
        return 1;
    }
}
